home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume13 / vn.jan.88 / part05 < prev    next >
Encoding:
Internet Message Format  |  1988-01-30  |  39.5 KB

  1. Subject:  v13i023:  VN newsreader, 1/88 version, Part05/05
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Bob Mcqueer <amdahl!rtech!rtech!bobm@UUNET.UU.NET>
  7. Posting-number: Volume 13, Issue 23
  8. Archive-name: vn.jan.88/part05
  9.  
  10. #! /bin/sh
  11. # This is a shell archive, meaning:
  12. # 1. Remove everything above the #! /bin/sh line.
  13. # 2. Save the resulting text in a file.
  14. # 3. Execute the file with /bin/sh (not csh) to create the files:
  15. #    session.c
  16. #    reader.c
  17. #    config.h
  18. export PATH; PATH=/bin:$PATH
  19. echo shar: extracting "'session.c'" '(19476 characters)'
  20. if test -f 'session.c'
  21. then
  22.     echo shar: will not over-write existing file "'session.c'"
  23. else
  24. cat << \SHAR_EOF > 'session.c'
  25. /*
  26. ** vn news reader.
  27. **
  28. ** session.c - top session loop
  29. **
  30. ** see copyright disclaimer / history in vn.c source file
  31. */
  32. #include <stdio.h>
  33. #include <setjmp.h>
  34. #include "config.h"
  35. #include "tty.h"
  36. #include "brk.h"
  37. #include "head.h"
  38. #include "tune.h"
  39. #include "node.h"
  40. #include "page.h"
  41. #include "vn.h"
  42.  
  43. extern NODE **Newsorder;
  44. extern char Erasekey, Killkey;
  45. extern int Rot;
  46. extern char *Ps1,*Printer;
  47. extern char *Orgdir,*Savefile;
  48. extern int Ncount, Cur_page, Lrec, L_allow, C_allow;
  49. extern int Headflag;
  50. extern PAGE Page;
  51. extern int Digest;
  52. extern char *No_msg;
  53. extern char *Hdon_msg;
  54. extern char *Hdoff_msg;
  55. extern char *Roton_msg;
  56. extern char *Rotoff_msg;
  57. extern char Cxitop[], Cxptoi[];
  58. extern char *Aformat;
  59. extern char *Contstr;
  60. extern char *Kl,*Kr,*Ku,*Kd;
  61. extern int Nounsub, Listfirst;
  62. extern char *List_sep;
  63. extern char *Version, *Vns_version;
  64.  
  65. extern int (*Headedit)();
  66.  
  67. static int C_info;
  68. static int Dskip, Drec;
  69.  
  70. static char *Unsub_msg = "Unsubscribed";
  71. static char *Egroup_msg = "Entire newsgroup";
  72.  
  73. static int Crec;
  74. static int Highrec;
  75.  
  76. /*
  77.     main session handler processing input commands
  78.  
  79.     NOTE: this is where a setjmp call is made to set the break reentry
  80.         location.  Keep the possible user states in mind.
  81. */
  82. session ()
  83. {
  84.     char alist [RECLEN], c;
  85.     int newg, i, count;
  86.     jmp_buf brkbuf;
  87.  
  88.     newg = new_groups();
  89.     tty_set (RAWMODE);
  90.     find_page (0);
  91.     Digest = 0;
  92.  
  93.     /* reentry point for break from within session interaction */
  94.     setjmp (brkbuf);
  95.     sig_set (BRK_SESS,brkbuf);
  96.     Headflag = FALSE;
  97.     Rot = 0;
  98.  
  99.     /* done this way so that user gets "really quit?" break treatment */
  100.     if (newg > 0)
  101.     {
  102.         printf ("\n%s",Contstr);
  103.         getnoctl();
  104.         newg = 0;
  105.     }
  106.  
  107.     /* list preview option - clear after first time for long jumps */
  108.     if (Listfirst)
  109.     {
  110.         /* tot_list settings will be overwritten in this case */
  111.         tot_list();
  112.         Listfirst = 0;
  113.     }
  114.  
  115.     /* if breaking from a digest, recover original page */
  116.     if (Digest)
  117.     {
  118.         find_page(Cur_page);
  119.         Digest = 0;
  120.     }
  121.     show ();
  122.     Crec = RECBIAS;
  123.     Highrec = Page.h.artnum + RECBIAS;
  124.     term_set (MOVE,0,Crec);
  125.  
  126.     /*
  127.         handle commands until QUIT, update global/local status
  128.         and display for each.
  129.      */
  130.     for (count = getkey(&c); c != QUIT; count = getkey(&c))
  131.     {
  132.         if ( srch_help(c,&i) != 0 || (Digest != 0 && i == 0))
  133.         {
  134.             preinfo (UDKFORM,Cxptoi[HELP]);
  135.             term_set (MOVE, 0, Crec);
  136.             continue;
  137.         }
  138.  
  139.         switch (c)
  140.         {
  141.         case HEADTOG:
  142.             if (Headedit != NULL)
  143.             {
  144.                 term_set(ERASE);
  145.                 (*Headedit)();
  146.                 show();
  147.                 term_set (MOVE,0,Crec);
  148.                 break;
  149.             }
  150.             if (Headflag)
  151.             {
  152.                 Headflag = FALSE;
  153.                 prinfo (Hdoff_msg);
  154.             }
  155.             else
  156.             {
  157.                 Headflag = TRUE;
  158.                 prinfo (Hdon_msg);
  159.             }
  160.             term_set (MOVE,0,Crec);
  161.             break;
  162.         case SETROT:
  163.             if (Rot == 0)
  164.             {
  165.                 Rot = 13;
  166.                 prinfo (Roton_msg);
  167.             }
  168.             else
  169.             {
  170.                 Rot = 0;
  171.                 prinfo (Rotoff_msg);
  172.             }
  173.             term_set (MOVE,0,Crec);
  174.             break;
  175.         case SSTAT:
  176.             count_msg ();
  177.             term_set (MOVE,0,Crec);
  178.             break;
  179.         case GRPLIST:
  180.             tot_list ();
  181.             show();
  182.             term_set (MOVE,0,Crec);
  183.             break;
  184.         case REDRAW:
  185.             show();
  186.             term_set (MOVE,0,Crec);
  187.             break;
  188.         case UNSUBSCRIBE:
  189.             new_sub(Page.h.group,0);
  190.             do_update(Unsub_msg);
  191.             term_set (MOVE,0,Crec);
  192.             break;
  193.  
  194.         case UPDATE:
  195.             new_read(Page.h.group,Page.b[Crec-RECBIAS].art_id);
  196.             wr_show ();
  197.             do_update("Updated to cursor");
  198.             term_set (MOVE,0,Crec);
  199.             break;
  200.         case UPALL:
  201.             new_read(Page.h.group,(Page.h.group)->highnum);
  202.             wr_show();
  203.             do_update(Egroup_msg);
  204.             term_set (MOVE,0,Crec);
  205.             break;
  206.         case ORGGRP:
  207.             new_read(Page.h.group,(Page.h.group)->orgrd);
  208.             wr_show();
  209.             do_update(Egroup_msg);
  210.             term_set (MOVE,0,Crec);
  211.             break;
  212.         case UPSEEN:
  213.             up_seen();
  214.             wr_show();
  215.             do_update("All pages displayed to this point updated");
  216.             term_set (MOVE,0,Crec);
  217.             break;
  218.         case ORGSTAT:
  219.             for (i = 0; i < Ncount; ++i)
  220.                 new_read(Newsorder[i],(Newsorder[i])->orgrd);
  221.             wr_show();
  222.             do_update("Original data recovered");
  223.             term_set (MOVE,0,Crec);
  224.             break;
  225.          case TOPMOVE:
  226.              Crec = RECBIAS;
  227.              term_set (MOVE, 0, Crec);
  228.              break;
  229.          case BOTMOVE:
  230.          case ALTBOTTOM:
  231.              Crec = Highrec - 1;
  232.              term_set (MOVE, 0, Crec);
  233.              break;
  234.          case MIDMOVE:
  235.              Crec = (RECBIAS + Highrec - 1) / 2;
  236.              if (Crec < RECBIAS)
  237.                  Crec = RECBIAS;
  238.              if (Crec >= Highrec)
  239.                  Crec = Highrec - 1;
  240.              term_set (MOVE, 0, Crec);
  241.              break;
  242.         case UP:
  243.             if (Crec != RECBIAS)
  244.             {
  245.                 Crec -= count;
  246.                 if (Crec < RECBIAS)
  247.                     Crec = RECBIAS;
  248.                 term_set (MOVE, 0, Crec);
  249.             }
  250.             else
  251.                 putchar ('\07');
  252.             break;
  253.         case DOWN:
  254.             if (Crec < (Highrec - 1))
  255.             {
  256.                 Crec += count;
  257.                 if (Crec >= Highrec)
  258.                     Crec = Highrec - 1;
  259.                 term_set (MOVE, 0, Crec);
  260.             }
  261.             else
  262.                 putchar ('\07');
  263.             break;
  264.         case MARK:
  265.         case ART_MARK:
  266.             count += Crec - 1;
  267.             if (count >= Highrec)
  268.                 count = Highrec - 1;
  269.             for (i=Crec; i <= count; ++i)
  270.             {
  271.                 if (Page.b[i-RECBIAS].art_mark != ART_MARK)
  272.                     Page.b[i-RECBIAS].art_mark = ART_MARK;
  273.                 else
  274.                     Page.b[i-RECBIAS].art_mark = ' ';
  275.                 if (i != Crec)
  276.                     term_set (MOVE, 0, i);
  277.                 printf ("%c\010",Page.b[i-RECBIAS].art_mark);
  278.             }
  279.             if (count != Crec)
  280.                 term_set (MOVE, 0, Crec);
  281.             write_page ();
  282.             break;
  283.         case UNMARK:
  284.             for (i=0; i < Page.h.artnum; ++i)
  285.             {
  286.                 if (Page.b[i].art_mark == ART_MARK)
  287.                 {
  288.                     Page.b[i].art_mark = ' ';
  289.                     term_set (MOVE, 0, i+RECBIAS);
  290.                     putchar (' ');
  291.                 }
  292.             }
  293.             term_set (MOVE, 0, Crec);
  294.             write_page ();
  295.             break;
  296.         case BACK:
  297.             count *= -1;    /* fall through */
  298.         case FORWARD:
  299.             if (forward (count) >= 0)
  300.                 show();
  301.             else
  302.                 preinfo ("No more pages");
  303.             term_set (MOVE,0,Crec);
  304.             break;
  305.         case DIGEST:
  306.             if (Digest)
  307.             {
  308.                 Digest = 0;
  309.                 find_page (Cur_page);
  310.                 show();
  311.                 Crec = Drec + RECBIAS + 1;
  312.                 Highrec = Page.h.artnum + RECBIAS;
  313.                 if (Crec >= Highrec)
  314.                     Crec = Highrec - 1;
  315.                 term_set (MOVE,0,Crec);
  316.                 break;
  317.             }
  318.             (Page.h.group)->flags |= FLG_ACC;
  319.             Dskip = count - 1;
  320.             Drec = Crec - RECBIAS;
  321.             if (digest_page(Drec,Dskip) >= 0)
  322.             {
  323.                 show();
  324.                 Crec = RECBIAS;
  325.                 Highrec = Page.h.artnum + RECBIAS;
  326.                 term_set (MOVE,0,Crec);
  327.                 break;
  328.             }
  329.             Digest = 0;
  330.             preinfo ("Can't unpack the article");
  331.             term_set (MOVE,0,Crec);
  332.             break;
  333.         case NEWGROUP:
  334.             if ((i = spec_group()) < 0)
  335.             {
  336.                 term_set (MOVE,0,Crec);
  337.                 break;
  338.             }
  339.             Digest = 0;
  340.             show();
  341.             Crec = RECBIAS;
  342.             Highrec = Page.h.artnum + RECBIAS;
  343.             term_set (MOVE,0,Crec);
  344.             break;
  345.  
  346.         case SAVE:
  347.             (Page.h.group)->flags |= FLG_ACC;
  348.             genlist (alist,Crec-RECBIAS,count);
  349.             savestr (alist);
  350.             term_set (MOVE,0,Crec);
  351.             break;
  352.         case SAVEALL:
  353.             (Page.h.group)->flags |= FLG_ACC;
  354.             genlist (alist,0,L_allow);
  355.             savestr (alist);
  356.             term_set (MOVE,0,Crec);
  357.             break;
  358.         case SAVESTRING:
  359.         case ALTSAVE:
  360.             (Page.h.group)->flags |= FLG_ACC;
  361.             userlist (alist);
  362.             savestr (alist);
  363.             term_set (MOVE,0,Crec);
  364.             break;
  365.         case READ:
  366.         case ALTREAD:
  367.             (Page.h.group)->flags |= FLG_ACC;
  368.             genlist (alist,Crec-RECBIAS,count);
  369.             readstr (alist,count);
  370.             break;
  371.         case READALL:
  372.             (Page.h.group)->flags |= FLG_ACC;
  373.             genlist (alist,0,L_allow);
  374.             readstr (alist,0);
  375.             break;
  376.         case READSTRING:
  377.             (Page.h.group)->flags |= FLG_ACC;
  378.             userlist (alist);
  379.             readstr (alist,0);
  380.             break;
  381.         case PRINT:
  382.             (Page.h.group)->flags |= FLG_ACC;
  383.             genlist (alist,Crec-RECBIAS,count);
  384.             printstr (alist);
  385.             term_set (MOVE,0,Crec);
  386.             break;
  387.         case PRINTALL:
  388.             (Page.h.group)->flags |= FLG_ACC;
  389.             genlist (alist,0,L_allow);
  390.             printstr (alist);
  391.             term_set (MOVE, 0, Crec);
  392.             break;
  393.         case PRINTSTRING:
  394.             (Page.h.group)->flags |= FLG_ACC;
  395.             userlist (alist);
  396.             printstr (alist);
  397.             term_set (MOVE, 0, Crec);
  398.             break;
  399.  
  400.         case HELP:
  401.             help ();
  402.             show ();
  403.             term_set (MOVE, 0, Crec);
  404.             break;
  405.         case UNESC:
  406.             user_str (alist,Ps1,1,"");
  407.             term_set (ERASE);
  408.             fflush (stdout);
  409.             tty_set (SAVEMODE);
  410.             if (chdir(Orgdir) < 0)
  411.                 printf ("change to original directory, %s, failed",Orgdir);
  412.             else
  413.             {
  414.                 system (alist);
  415.                 tty_set (RESTORE);
  416.                 term_set (RESTART);
  417.             }
  418.             printf (Contstr);
  419.             getnoctl ();
  420.             vns_gset(Page.h.name);
  421.             show ();
  422.             term_set (MOVE, 0, Crec);
  423.             break;
  424.         case PRTVERSION:
  425.             prinfo("%s %s", Version, Vns_version);
  426.             term_set (MOVE, 0, Crec);
  427.             break;
  428.         default:
  429.             preinfo("Unhandled key: %c", c);
  430.             break;
  431.         }
  432.     }
  433.  
  434.     Digest = 0;
  435.     for (i=0; i < Ncount; ++i)
  436.     {
  437.         if ((Newsorder[i])->rdnum < (Newsorder[i])->pgrd)
  438.             break;
  439.     }
  440.     if (i < Ncount)
  441.     {
  442.         user_str (alist,"Some displayed pages not updated - update ? ",
  443.                             1, QUIT_ANSWER);
  444.         if (alist[0] == 'y')
  445.             up_seen();
  446.     }
  447.     sig_set (BRK_OUT);
  448. }
  449.  
  450. /*
  451. ** update status of Newsgroups to all seen pages
  452. */
  453. up_seen()
  454. {
  455.     int i;
  456.  
  457.     for (i = 0; i < Ncount; ++i)
  458.     {
  459.         if (Nounsub && ((Newsorder[i])->flags & FLG_SUB) == 0)
  460.         {
  461.             new_read(Newsorder[i],(Newsorder[i])->highnum);
  462.             continue;
  463.         }
  464.         if ((Newsorder[i])->rdnum < (Newsorder[i])->pgrd)
  465.             new_read(Newsorder[i],(Newsorder[i])->pgrd);
  466.     }
  467. }
  468.  
  469. /*
  470.     count_msg displays count information
  471. */
  472. count_msg ()
  473. {
  474.     int i, gpnum, gscan, gpage;
  475.     unsigned long mask;
  476.     gpnum = 1;
  477.     for (gscan = gpage = i = 0; i<Ncount; ++i)
  478.     {
  479.         if (((Newsorder[i])->flags & FLG_PAGE) != 0)
  480.         {
  481.             if (((Newsorder[i])->pnum + (Newsorder[i])->pages - 1) < Cur_page)
  482.                 ++gpnum;
  483.             ++gpage;
  484.             for (mask=1; mask != 0L; mask <<= 1)
  485.                 if (((Newsorder[i])->pgshwn & mask) != 0L)
  486.                     ++gscan;
  487.         }
  488.     }
  489.     prinfo (CFORMAT,Cur_page+1,Lrec+1,gscan,gpnum,gpage);
  490. }
  491.  
  492. /*
  493.     forward utility handles paging
  494. */
  495. static
  496. forward (count)
  497. int count;
  498. {
  499.     if (!Digest)
  500.     {
  501.         if ((count < 0 && Cur_page <= 0) || (count > 0 && Cur_page >= Lrec))
  502.             return (-1);
  503.         Cur_page += count;
  504.         if (Cur_page < 0)
  505.             Cur_page = 0;
  506.         if (Cur_page > Lrec)
  507.             Cur_page = Lrec;
  508.         find_page (Cur_page);
  509.         Crec = RECBIAS;
  510.         Highrec = Page.h.artnum + RECBIAS;
  511.         return (0);
  512.     }
  513.     /*
  514.     ** in digests, paging past the end of the digest returns to
  515.     ** page extracted from.
  516.     */
  517.     if (Dskip > 0 && (Dskip + count*L_allow) < 0)
  518.         Dskip = 0;
  519.     else
  520.         Dskip += count * L_allow;
  521.     find_page (Cur_page);
  522.     if (Dskip >= 0)
  523.     {
  524.         if (digest_page(Drec,Dskip) >= 0)
  525.         {
  526.             Crec = RECBIAS;
  527.             Highrec = Page.h.artnum + RECBIAS;
  528.             return (0);
  529.         }
  530.     }
  531.     Digest = 0;
  532.     Crec = Drec + RECBIAS + 1;
  533.     Highrec = Page.h.artnum + RECBIAS;
  534.     if (Crec >= Highrec)
  535.         Crec = Highrec - 1;
  536.     return (0);
  537. }
  538.  
  539. /*
  540.     generate list of articles on current page,
  541.     count articles, starting with first.
  542. */
  543. static
  544. genlist (list,first,count)
  545. char *list;
  546. int first,count;
  547. {
  548.     int i;
  549.     for (i=first; i < Page.h.artnum && count > 0; ++i)
  550.     {
  551.         sprintf (list,"%d ",Page.b[i].art_id);
  552.         list += strlen(list);
  553.         --count;
  554.     }
  555. }
  556.  
  557. /*
  558.     send list of articles to printer
  559. */
  560. static
  561. printstr (s)
  562. char *s;
  563. {
  564.     char cmd [RECLEN];
  565.     char fn[L_tmpnam];
  566.     char dsave[RECLEN];    /* save list for unlinking */
  567.  
  568.     prinfo ("preparing print command ....");
  569.  
  570.     if (Digest)
  571.     {
  572.         dig_list (s);
  573.         strcpy(dsave,s);
  574.     }
  575.  
  576.     if (*s != '\0')
  577.     {
  578.         tmpnam(fn);
  579.         if (art_xfer(fn,s,"w") != 0)
  580.         {
  581.             preinfo("Couldn't open temporary file");
  582.             return;
  583.         }
  584.         sprintf (cmd,"%s %s 2>/dev/null",Printer,fn);
  585.         if (system (cmd) == 0)
  586.             prinfo ("Sent to printer");
  587.         else
  588.             preinfo ("Print failed");
  589.         unlink(fn);
  590.     }
  591.     else
  592.         preinfo (No_msg);
  593.  
  594.     if (Digest)
  595.         dig_ulist (dsave);
  596. }
  597.  
  598. /*
  599.     read a list of articles.
  600. */
  601. readstr (s,count)
  602. char *s;
  603. int count;
  604. {
  605.     char *strtok();
  606.     char *fn[MAXARTLIST+1];
  607.     int pc, num, i;
  608.  
  609.     /* we pre-process tokens to release strtok() for further use */
  610.     fn[0] = strtok(s,List_sep);
  611.     for (num=0; fn[num] != NULL; fn[(++num)] = strtok(NULL,List_sep))
  612.         if (num >= MAXARTLIST)
  613.             break;
  614.     fn[num] = NULL;
  615.  
  616.     if (fn[0] != NULL)
  617.     {
  618.         term_set (ERASE);
  619.         for (i=0; i < num && readfile(fn[i], fn[i+1] ,&pc) >= 0; ++i)
  620.         {
  621.             if (Digest)
  622.                 unlink (fn[i]);
  623.         }
  624.         if (Digest && fn[i] != NULL)
  625.             unlink (fn[i]);
  626.         if (pc != 0)
  627.             forward (pc);
  628.         else
  629.         {
  630.             Crec += count;
  631.             if (Crec >= Highrec)
  632.                 Crec = Highrec - 1;
  633.         }
  634.         show ();
  635.         term_set (MOVE, 0, Crec);
  636.     }
  637.     else
  638.     {
  639.         preinfo ("%s",No_msg);
  640.         term_set (MOVE, 0, Crec);
  641.     }
  642. }
  643.  
  644. /*
  645.     concatenate articles to save file with appropriate infoline messages.
  646.     prompt for save file, giving default.  If save file begins with "|"
  647.     handle as a filter to pipe to.  NOTE - every user specification of
  648.     a new Savefile "loses" some storage, but it shouldn't be a very great
  649.     amount.
  650. */
  651. static
  652. savestr (s)
  653. char *s;
  654. {
  655.     char *ptr, newfile [MAX_C+1], msg[RECLEN];
  656.     char *str_store();
  657.     char dsave[RECLEN];
  658.  
  659.     if (Digest)
  660.     {
  661.         dig_list (s);
  662.         strcpy(dsave,s);
  663.     }
  664.  
  665.     if (*s != '\0')
  666.     {
  667.         user_str (newfile,"save file ? ",1,Savefile);
  668.         ptr = newfile;
  669.         if (*ptr == '|')
  670.         {
  671.             term_set (ERASE);
  672.             fflush (stdout);
  673.             save_art(s,ptr,msg);
  674.             printf ("%s\n%s",msg,Contstr);
  675.             getnoctl ();
  676.             show ();
  677.         }
  678.         else
  679.         {
  680.             prinfo("saving ....");
  681.             if (*ptr == '\0')
  682.                 ptr = Savefile;
  683.             else
  684.                 Savefile = str_store(ptr);
  685.             if (save_art(s,Savefile,msg) != 0)
  686.                 preinfo(msg);
  687.             else
  688.                 prinfo(msg);
  689.         }
  690.     }
  691.     else
  692.         preinfo (No_msg);
  693.  
  694.     if (Digest)
  695.         dig_ulist (dsave);
  696. }
  697.  
  698. /*
  699.     basic page display routine.  erase screen and format current page
  700. */
  701. static
  702. show ()
  703. {
  704.     int i;
  705.     unsigned long mask;
  706.     char helpstr[40]; 
  707.  
  708.     term_set (ERASE);
  709.     C_info = 0;
  710.     i = Cur_page - (Page.h.group)->pnum + 1;
  711.     if (Digest)
  712.         printf (DHFORMAT,Page.h.name);
  713.     else
  714.         printf (HFORMAT,Page.h.name,i,(Page.h.group)->pages);
  715.  
  716.     mask = 1L << (i-1);
  717.     (Page.h.group)->pgshwn |= mask;
  718.     mask = 1;
  719.     for (--i; i > 0 && (mask & (Page.h.group)->pgshwn) != 0 ; --i)
  720.         mask <<= 1;
  721.     if (i <= 0)
  722.         (Page.h.group)->pgrd = Page.b[(Page.h.artnum)-1].art_id;
  723.  
  724.     for (i=0; i < Page.h.artnum; ++i)
  725.     {
  726.         if (Digest)
  727.         {
  728.             printf(Aformat,Page.b[i].art_mark,ART_UNWRITTEN,Page.b[i].art_id);
  729.             printf("%s",Page.b[i].art_t);
  730.             continue;
  731.         }
  732.  
  733.         if ((Page.h.group)->rdnum >= Page.b[i].art_id)
  734.             printf(Aformat,Page.b[i].art_mark,ART_WRITTEN,Page.b[i].art_id);
  735.         else
  736.             printf(Aformat,Page.b[i].art_mark,ART_UNWRITTEN,Page.b[i].art_id);
  737.         printf("%s",Page.b[i].art_t);
  738.     }
  739.  
  740.     sprintf(helpstr,HELPFORM,Cxptoi[HELP]);
  741.     if (!Digest && ((Page.h.group)->flags & FLG_SUB) == 0)
  742.         prinfo ("%s, %s",Unsub_msg,helpstr);
  743.     else
  744.         prinfo (helpstr);
  745. }
  746.  
  747. /*
  748.     update written status marks on screen
  749. */
  750. static
  751. wr_show ()
  752. {
  753.     int i,row;
  754.     char c;
  755.  
  756.     row = RECBIAS;
  757.     for (i=0; i < Page.h.artnum; ++i)
  758.     {
  759.         term_set (MOVE,WRCOL,row);
  760.         if ((Page.h.group)->rdnum >= Page.b[i].art_id)
  761.             c = ART_WRITTEN;
  762.         else
  763.             c = ART_UNWRITTEN;
  764.         printf("%c",c);
  765.         ++row;
  766.     }
  767. }
  768.  
  769. /*
  770.     obtain user input of group name, becomes current page if valid.
  771.     returns -1 or page number.  calling routine does the show, if needed
  772. */
  773. static
  774. spec_group ()
  775. {
  776.     char nbuf [MAX_C + 1];
  777.     NODE *p, *hashfind();
  778.  
  779.     user_str(nbuf,"Newsgroup ? ",1,"");
  780.  
  781.     if (*nbuf == '\0' || (p = hashfind(nbuf)) == NULL)
  782.     {
  783.         preinfo ("Not a newsgroup");
  784.         return (-1);
  785.     }
  786.     if ((p->flags & FLG_PAGE) == 0)
  787.     {
  788.         if ((p->flags & FLG_SUB) == 0)
  789.         {
  790.             new_sub(p,FLG_SUB);
  791.             do_update("Not subscribed: resubscribed for next reading session");
  792.         }
  793.         else
  794.             prinfo ("No news for that group");
  795.         return (-1);
  796.     }
  797.     if ((p->flags & FLG_SUB) == 0)
  798.     {
  799.         new_sub(p,FLG_SUB);
  800.         do_update("Resubscribed");
  801.     }
  802.     find_page (p->pnum);
  803.     return (p->pnum);
  804. }
  805.  
  806. /*
  807.     obtain user input with prompt p.  Optionally on info line.
  808.     handle erase and kill characters, suppresses leading
  809.     white space.  Use defstr as the editable default user input.
  810.     If on info line, cursor is not moved anywhere whe done, otherwise
  811.     a <CR><LF> is done after input.  Should be in raw mode to use
  812.     this routine.  Used from outside this source file so that we
  813.     only have to do erase / kill key stuff one place.
  814. */
  815. user_str (s,p,iline,defstr)
  816. char *s;
  817. char *p;
  818. int iline;
  819. char *defstr;
  820. {
  821.     int i,idx,len;
  822.  
  823.     if (iline)
  824.     {
  825.          prinfo ("%s%s",p,defstr);
  826.         idx = C_info;
  827.     }
  828.     else
  829.     {
  830.          printf ("%s%s",p,defstr);
  831.         idx = strlen(p);
  832.     }
  833.  
  834.     len = strlen(defstr);
  835.      for (i=0; i < len; i++)
  836.          s[i] = defstr[i];
  837.  
  838.     for (i=len; idx < C_allow && (s[i] = getchar() & 0x7f) != '\012' && s[i] != '\015'; ++i)
  839.     {
  840.         if (s[i] == Erasekey)
  841.         {
  842.             if (i > 0)
  843.             {
  844.                 term_set (RUBSEQ);
  845.                 i -= 2;
  846.                 --idx;
  847.             }
  848.             else
  849.                 i = -1;
  850.             continue;
  851.         }
  852.         if (s[i] == Killkey)
  853.         {
  854.              if (iline)
  855.              {
  856.                  prinfo ("%s",p);
  857.                  idx = C_info;
  858.              }
  859.              else
  860.              {
  861.                  printf ("\r%s",p);
  862.                  term_set(ZAP,strlen(p),idx);
  863.                  fflush(stdout);
  864.                  idx = strlen(p);
  865.              }
  866.             i = -1;
  867.             continue;
  868.         }
  869.         /* no leading spaces */
  870.         if (s[i] == ' ' && i == 0)
  871.         {
  872.             i = -1;
  873.             putchar('\07');
  874.             continue;
  875.         }
  876.         /* no controls */
  877.         if (s[i] < ' ' || s[i] == '\177')
  878.         {
  879.             --i;
  880.             putchar('\07');
  881.             continue;
  882.         }
  883.         ++idx;
  884.         putchar (s[i]);
  885.     }
  886.  
  887.     if (iline)
  888.         C_info = idx;
  889.     else
  890.         printf("\r\n");
  891.  
  892.     s[i] = '\0';
  893. }
  894.  
  895. /*
  896.     print something on the information line,
  897.     clearing any characters not overprinted.
  898.     preinfo includes reverse video and a bell for error messages.
  899. */
  900. preinfo (s,a,b,c,d,e,f)
  901. {
  902.     int l;
  903.     char buf[RECLEN];
  904.  
  905.     term_set (MOVE,0,INFOLINE);
  906.     putchar ('\07');
  907.     term_set (ONREVERSE);
  908.     sprintf (buf,s,a,b,c,d,e,f);
  909.     printf (" %s ",buf);
  910.     term_set (OFFREVERSE);
  911.     l = strlen(buf) + 2;
  912.     if (l < C_info)
  913.         term_set (ZAP,l,C_info);
  914.     C_info = l;
  915.     fflush(stdout);
  916. }
  917.  
  918. prinfo (s,a,b,c,d,e,f)
  919. char *s;
  920. long a,b,c,d,e,f;
  921. {
  922.     int l;
  923.     char buf[RECLEN];
  924.     term_set (MOVE,0,INFOLINE);
  925.     sprintf (buf,s,a,b,c,d,e,f);
  926.     printf ("%s",buf);
  927.     l = strlen(buf);
  928.     if (l < C_info)
  929.         term_set (ZAP,l,C_info);
  930.     C_info = l;
  931.     fflush(stdout);
  932. }
  933.  
  934. static
  935. tot_list ()
  936. {
  937.     int i,max,len;
  938.     char c;
  939.     char ff[MAX_C+1];
  940.  
  941.     term_set (ERASE);
  942.  
  943.     for (max=i=0; i < Ncount; ++i)
  944.     {
  945.         if ((Newsorder[i])->pages == 0)
  946.             continue;
  947.         if ((len = strlen((Newsorder[i])->nd_name)) > max)
  948.             max = len;
  949.     }
  950.  
  951.     sprintf (ff,"%%4d %%%ds: %%3d new %%3d updated\n",max);
  952.  
  953.     for (len=i=0; i < Ncount; ++i)
  954.     {
  955.         if ((Newsorder[i])->pages == 0)
  956.             continue;
  957.         printf (ff, i, (Newsorder[i])->nd_name,
  958.                 (Newsorder[i])->highnum - (Newsorder[i])->orgrd,
  959.                 (Newsorder[i])->rdnum - (Newsorder[i])->orgrd);
  960.         ++len;
  961.         if (len == L_allow && i < (Ncount-1))
  962.         {
  963.             printf("\nr - return, n - new group, other to continue ... ");
  964.             if ((c = getnoctl()) == 'r' || c == 'n')
  965.                 break;
  966.             printf ("\n\n");
  967.             len = 0;
  968.         }
  969.     }
  970.     if (i >= Ncount)
  971.     {
  972.         printf("n - new group, other to return ... ");
  973.         c = getnoctl();
  974.     }
  975.  
  976.     /* c will remain 'n' while user chooses bad newsgroups */
  977.     while (c == 'n')
  978.     {
  979.         printf("\n");
  980.         user_str(ff,"Newsgroup number ? ",0,"");
  981.         i = atoi(ff);
  982.          if (i < 0 || i >= Ncount || (Newsorder[i])->pages == 0)
  983.         {
  984.              printf("\nBad newsgroup number\n");
  985.              printf("n - new group, other to return ... ");
  986.             c = getnoctl();
  987.             continue;
  988.          }
  989.          find_page((Newsorder[i])->pnum);
  990.         Crec = RECBIAS;
  991.         Highrec = Page.h.artnum + RECBIAS;
  992.         c = '\0';
  993.     }
  994. }
  995.  
  996. /*
  997. ** call vns_write if anything has changed, then wipe FLG_ECHG bits
  998. ** also produce message(s)
  999. */
  1000. static
  1001. do_update(msg)
  1002. char *msg;
  1003. {
  1004.     int i;
  1005.  
  1006.     for (i=0; i < Ncount; ++i)
  1007.         if(((Newsorder[i])->flags & FLG_ECHG) != 0)
  1008.             break;
  1009.     if (i < Ncount)
  1010.     {
  1011.         prinfo("Writing news status");
  1012.         vns_write(Newsorder,Ncount);
  1013.         for (i=0; i < Ncount; ++i)
  1014.             (Newsorder[i])->flags &= ~FLG_ECHG;
  1015.     }
  1016.     prinfo(msg);
  1017. }
  1018.  
  1019. /*
  1020. ** set a new rdnum value.  If a change, set FLG_ECHG
  1021. */
  1022. static
  1023. new_read(n,rd)
  1024. NODE *n;
  1025. int rd;
  1026. {
  1027.     if (n->rdnum != rd)
  1028.     {
  1029.         n->rdnum = rd;
  1030.         n->flags |= FLG_ECHG;
  1031.     }
  1032. }
  1033.  
  1034. /*
  1035. ** set a new subscription bit.  bit argument is either 0 or FLG_SUB.
  1036. */
  1037. static
  1038. new_sub(n,bit)
  1039. NODE *n;
  1040. unsigned bit;
  1041. {
  1042.     /*
  1043.     ** since bit is 0 or FLG_SUB, we could get tricky with ^
  1044.     ** but this is clearer
  1045.     */
  1046.     if (bit != 0 && (n->flags & FLG_SUB) == 0)
  1047.         n->flags |= FLG_SUB|FLG_ECHG;
  1048.     else
  1049.     {
  1050.         if (bit == 0 && (n->flags & FLG_SUB) != 0)
  1051.         {
  1052.             n->flags &= ~FLG_SUB;
  1053.             n->flags |= FLG_ECHG;
  1054.         }
  1055.     }
  1056. }
  1057. SHAR_EOF
  1058. fi # end of overwriting check
  1059. echo shar: extracting "'reader.c'" '(15750 characters)'
  1060. if test -f 'reader.c'
  1061. then
  1062.     echo shar: will not over-write existing file "'reader.c'"
  1063. else
  1064. cat << \SHAR_EOF > 'reader.c'
  1065. /*
  1066. ** vn news reader.
  1067. **
  1068. ** reader.c - article reading interface - "more" like.
  1069. **
  1070. ** see copyright disclaimer / history in vn.c source file
  1071. */
  1072.  
  1073. #include <stdio.h>
  1074. #include <sys/types.h>
  1075. #include "tty.h"
  1076. #include "config.h"
  1077. #include "tune.h"
  1078. #include "head.h"
  1079. #include "reader.h"
  1080. #include "brk.h"
  1081. #include "node.h"
  1082. #include "page.h"
  1083. #include "vn.h"
  1084.  
  1085. #define PERTAB 8    /* tab expansion factor */
  1086. #define BACKTRACK 24
  1087.  
  1088. extern char *Printer,*Editor,*Mailer,*Poster,*Orgdir,*Savefile,*Savedir,*Ccfile;
  1089. extern int L_allow;
  1090. extern int C_allow;
  1091. extern int Rot;
  1092. extern int Headflag;
  1093. extern int Digest;
  1094. extern int More;
  1095. extern char *No_msg;
  1096. extern char *Roton_msg;
  1097. extern char *Rotoff_msg;
  1098. extern char *Hdon_msg;
  1099. extern char *Hdoff_msg;
  1100.  
  1101. extern PAGE Page;
  1102.  
  1103. extern int (*Massage)();
  1104. extern int (*Postfunc)();
  1105. extern int (*Mailfunc)();
  1106.  
  1107. extern char Cxrtoi[], Cxitor[];
  1108.  
  1109. static FILE *Fpread;
  1110. static char *Fname;
  1111. static char *Lookahead;
  1112. static int Rlines;
  1113. static int Hlines;
  1114. static long Rew_pos;
  1115.  
  1116. /*
  1117.     readfile presents article:
  1118.         fn = name of article.
  1119.         sn - name of next article, NULL if last.
  1120.         pages - pages to advance on return, if applicable
  1121.     returns 0 for "continue", <0 for "quit"
  1122.  
  1123.     calls sig_set(BRK_READ / BRK_RFIN) around reading article.
  1124. */
  1125. readfile (fn,sn,pages)
  1126. char *fn;
  1127. char *sn;
  1128. int *pages;
  1129. {
  1130.     ARTHEADER hdr;
  1131.     FILE *fopen();
  1132.     int lines,percent;
  1133.     int i;
  1134.     int top, bottom;
  1135.     int step;
  1136.     char c,  buf[RECLEN];
  1137.     char lasave[RECLEN];
  1138.     char pstr[24], dgname[48];
  1139.     char getpgch(), *index(), *digest_extract(), *tgetstr();
  1140.     char *any;
  1141.     FILE *vns_aopen();
  1142.     long ftell();
  1143.  
  1144.     Fname = fn;
  1145.     *pages = 0;
  1146.     step = FALSE;    /* Boolean; to indicate user input a <RET> (PG_STEP) */
  1147.  
  1148.     term_set(ERASE);
  1149.     sig_set(BRK_READ,&Fpread);
  1150.  
  1151.     any = "any key to continue .... ";
  1152.  
  1153.     if (Digest)
  1154.     {
  1155.         lines = atoi(Fname);
  1156.         if ((Fname = digest_extract(dgname,lines,&hdr,&Rew_pos)) == NULL)
  1157.         {
  1158.             rerrmsg("couldn't extract article %d from digest",lines);
  1159.             printf(any);
  1160.             getnoctl();
  1161.             sig_set(BRK_RFIN);
  1162.             return (0);
  1163.         }
  1164.         if ((Fpread = fopen(Fname,"r")) == NULL)
  1165.         {
  1166.             rerrmsg("couldn't open %s",Fname);
  1167.             printf(any);
  1168.             getnoctl();
  1169.             sig_set(BRK_RFIN);
  1170.             return (0);
  1171.         }
  1172.         fseek(Fpread,Rew_pos,0);
  1173.     }
  1174.     else
  1175.     {
  1176.         if ((Fpread = vns_aopen(atoi(Fname),&hdr)) == NULL)
  1177.         {
  1178.             rerrmsg("couldn't open article %s",Fname);
  1179.             printf(any);
  1180.             getnoctl();
  1181.             sig_set(BRK_RFIN);
  1182.             return (0);
  1183.         }
  1184.         Rew_pos = ftell(Fpread);
  1185.     }
  1186.  
  1187.     Hlines = hdr.hlines;
  1188.     printf (ANFORM,Fname,Cxrtoi[PG_HELP]);
  1189.  
  1190.     lines = 0;
  1191.  
  1192.     if (Headflag)
  1193.     {
  1194.         rewind(Fpread);
  1195.         Rlines = 0;
  1196.     }
  1197.     else
  1198.     {
  1199.         /* use do_out to guard against control sequences */
  1200.         Rlines = Hlines;
  1201.         for (i=0; i < hdr.show_num; ++i)
  1202.             lines += do_out((hdr.show)[i],L_allow-lines);
  1203.         lines += do_out("",L_allow-lines);
  1204.     }
  1205.  
  1206.     /* will return out of outer while loop */
  1207.     Lookahead = NULL;
  1208.     while (1)
  1209.     {
  1210.         /*
  1211.         ** lines counts folded lines from do_out.
  1212.         ** globals Hlines and Rlines refer to records.
  1213.         ** If Lookahead is null after this loop, we've
  1214.         ** hit EOF.
  1215.         */
  1216.         if (Lookahead != NULL && More && !step)
  1217.         {
  1218.             char *looktmp;
  1219.  
  1220.             /*
  1221.             ** Save Lookahead because `do_out' nukes it.
  1222.             ** Perhaps we could just use `printf' here
  1223.             ** but for now we'll play it safe. - GKE 12/26/87
  1224.             */
  1225.             looktmp = Lookahead;
  1226.             term_set(ERASE);
  1227.             /* 
  1228.             ** The following presents the last line of the
  1229.             ** previous page in reversed video, as the first line
  1230.             ** of the current page, `rn'-stylee.  Since `rn'
  1231.             ** uses an option to enable/disable this, remove the
  1232.             ** two `term_set's if not to your liking.
  1233.             */
  1234.             term_set(ONREVERSE);
  1235.             do_out(lasave,1);
  1236.             term_set(OFFREVERSE);
  1237.             Lookahead = looktmp;
  1238.         }
  1239.         lines += do_out(Lookahead,L_allow-lines);
  1240.         while (1)
  1241.         {
  1242.             if (Lookahead == NULL)
  1243.             {
  1244.                 if (fgets(buf,RECLEN-1,Fpread) == NULL)
  1245.                     break;
  1246.                 Lookahead = buf;
  1247.                 if (Rot != 0 && Rlines >= Hlines)
  1248.                     rot_line(buf);
  1249.                 ++Rlines;
  1250.             }
  1251.             if (lines >= L_allow)
  1252.                 break;
  1253.             if (More)
  1254.                 strcpy(lasave,Lookahead);
  1255.             lines += do_out(Lookahead,L_allow-lines);
  1256.         }
  1257.  
  1258.         if (Lookahead != NULL)
  1259.         {
  1260.             /*
  1261.             ** calculation is truncated rather than rounded,
  1262.             ** so we shouldn't get "100%".  Subtract 2 for
  1263.             ** 1 line lookahead and empty line at beginning
  1264.             ** of article.
  1265.             */
  1266.             if (Headflag)
  1267.             {
  1268.                 top = (Rlines-2)*100;
  1269.                 bottom = hdr.lines + Hlines;
  1270.             }
  1271.             else
  1272.             {
  1273.                 top = (Rlines-Hlines-2)*100;
  1274.                 bottom = hdr.lines;
  1275.             }
  1276.             /*
  1277.             ** protect against division by zero -
  1278.             ** shouldn't actually come up zero at this
  1279.             ** point if vns_aopen is sane. 999 will let user
  1280.             ** know the percentage is obviously wrong.
  1281.             */
  1282.             if (bottom != 0)
  1283.                 percent = top/bottom;
  1284.             else
  1285.                 percent = 999;
  1286.             sprintf (pstr,PAGE_MID,percent);
  1287.         }
  1288.         else
  1289.         {
  1290.             if (sn == NULL)
  1291.                 strcpy (pstr,PAGE_END);
  1292.             else
  1293.             strcpy (pstr,PAGE_NEXT);
  1294.         }
  1295.         c = getpgch(pstr,&hdr);
  1296.  
  1297.         /*
  1298.             handle user input:
  1299.             CAUTION!!  return cases must close Fpread.
  1300.         */
  1301.         step = FALSE;
  1302.         switch (c)
  1303.         {
  1304.         case PG_NEXT:
  1305.             if (Digest)
  1306.             {
  1307.                 fclose (Fpread);
  1308.                 unlink (Fname);
  1309.             }
  1310.             else
  1311.                 vns_aclose (Fpread);
  1312.             sig_set(BRK_RFIN);
  1313.             return (0);
  1314.         case PG_FLIP:
  1315.             *pages = 1;    /* fall through */
  1316.         case PG_QUIT:
  1317.             if (Digest)
  1318.             {
  1319.                 fclose (Fpread);
  1320.                 unlink (Fname);
  1321.             }
  1322.             else
  1323.                 vns_aclose (Fpread);
  1324.             sig_set(BRK_RFIN);
  1325.             return (-1);
  1326.         case PG_REWIND:
  1327.             if (Headflag)
  1328.             {
  1329.                 Rlines = 0;
  1330.                 rewind (Fpread);
  1331.             }
  1332.             else
  1333.             {
  1334.                 fseek (Fpread,Rew_pos,0);
  1335.                 Rlines = Hlines;
  1336.             }
  1337.             Lookahead = NULL;
  1338.             lines = 2 - RECBIAS;
  1339.             break;
  1340.         case PG_SEARCH:
  1341.             searcher(buf);
  1342.             lines = 2 - RECBIAS;
  1343.             lines += do_out(buf,L_allow-lines);
  1344.             break;
  1345.         case PG_WIND:
  1346.             fseek (Fpread,0L,2);
  1347.             lines = 2 - RECBIAS;
  1348.             Lookahead = NULL;
  1349.             break;
  1350.         case PG_STEP:
  1351.             if (Lookahead == NULL)
  1352.             {
  1353.                 if (Digest)
  1354.                 {
  1355.                     fclose (Fpread);
  1356.                     unlink (Fname);
  1357.                 }
  1358.                 else
  1359.                     vns_aclose (Fpread);
  1360.                 sig_set(BRK_RFIN);
  1361.                 return (0);
  1362.             }
  1363.             lines = L_allow - 1;
  1364.             step = TRUE;    /* Temporarily disable paging */
  1365.             break;
  1366.         default:
  1367.             if (Lookahead == NULL)
  1368.             {
  1369.                 if (Digest)
  1370.                 {
  1371.                     fclose (Fpread);
  1372.                     unlink (Fname);
  1373.                 }
  1374.                 else
  1375.                     vns_aclose (Fpread);
  1376.                 sig_set(BRK_RFIN);
  1377.                 return (0);
  1378.             }
  1379.             lines = 2 - RECBIAS;
  1380.             break;
  1381.         }
  1382.     }
  1383. }
  1384.  
  1385. /*
  1386.     getpgch prints prompt and gets command from user
  1387.     handles "mail", "save" and "followup" internally
  1388.     as well as flag resets.
  1389. */
  1390. static char
  1391. getpgch(prompt,hdr)
  1392. char *prompt;
  1393. ARTHEADER *hdr;
  1394. {
  1395.     char c;
  1396.     int ic;
  1397.     term_set (ONREVERSE);
  1398.     printf("%s\015",prompt);
  1399.     term_set (OFFREVERSE);
  1400.     while ((ic=getnoctl()) != EOF)
  1401.     {
  1402.         switch (c = Cxitor[ic])
  1403.         {
  1404.         case SETROT:
  1405.             term_set (ZAP,0,PPR_MAX);
  1406.             if (Rot == 0)
  1407.             {
  1408.                 Rot = 13;
  1409.                 printf ("%s\n",Roton_msg);
  1410.             }
  1411.             else
  1412.             {
  1413.                 Rot = 0;
  1414.                 printf ("%s\n",Rotoff_msg);
  1415.             }
  1416.             if (Lookahead != NULL && Rlines > Hlines)
  1417.                 rot_line(Lookahead);
  1418.             break;
  1419.         case HEADTOG:
  1420.             term_set (ZAP,0,PPR_MAX);
  1421.             if (Headflag)
  1422.             {
  1423.                 Headflag = FALSE;
  1424.                 printf ("%s\n",Hdoff_msg);
  1425.             }
  1426.             else
  1427.             {
  1428.                 Headflag = TRUE;
  1429.                 printf ("%s\n",Hdon_msg);
  1430.             }
  1431.             break;
  1432.         case PG_HELP:
  1433.             term_set (ZAP,0,PPR_MAX);
  1434.             help_rd ();
  1435.             break;
  1436.         case PG_REPLY:
  1437.             mail (hdr);
  1438.             break;
  1439.         case PG_FOLLOW:
  1440.             followup (hdr);
  1441.             break;
  1442.         case SAVE:
  1443.             saver ();
  1444.             break;
  1445.         case PRINT:
  1446.             printr ();
  1447.             break;
  1448.         default:
  1449.             term_set (ZAP,0,PPR_MAX);
  1450.             return (c);
  1451.         }
  1452.  
  1453.         term_set (ONREVERSE);
  1454.         printf("%s\015",prompt);
  1455.         term_set (OFFREVERSE);
  1456.     }
  1457.     term_set (ZAP,0,PPR_MAX);
  1458.     return (c);
  1459. }
  1460.  
  1461. /*
  1462.     save article.  Like its "session" counterpart, this loses storage
  1463.     if the user specifies a new file, but it should not be significant
  1464. */
  1465. static
  1466. saver ()
  1467. {
  1468.     char buf[RECLEN],msg[RECLEN],*str_store();
  1469.  
  1470.     user_str (buf,"save file ? ",0,Savefile);
  1471.     if (buf[0] != '\0' && buf[0] != '|')
  1472.         Savefile = str_store(buf);
  1473.     if (save_art(Fname,buf,msg) != 0)
  1474.         rerrmsg(msg);
  1475.     else
  1476.         printf("%s\n",msg);
  1477. }
  1478.  
  1479. /*
  1480.     invoke editor on new temp file, mail using reply line,
  1481.     possibly first allowing user to overide the reply (not INLETTER)
  1482. */
  1483. static
  1484. mail (hdr)
  1485. ARTHEADER *hdr;
  1486. {
  1487.     char *new, fn[L_tmpnam], cmd [RECLEN+60], *rprompt ();
  1488.     int i;
  1489.     FILE *fp, *fopen();
  1490.  
  1491.     if (Massage != NULL)
  1492.         (*Massage)(hdr);
  1493.  
  1494.     if (hdr->mail_err != NULL)
  1495.     {
  1496.         rerrmsg(hdr->mail_err);
  1497.         return;
  1498.     }
  1499.  
  1500.     tmpnam (fn);
  1501.     if ((fp = fopen(fn,"w")) == NULL)
  1502.     {
  1503.         rerrmsg("can't open temp file, %s",fn);
  1504.         return;
  1505.     }
  1506.  
  1507.     for (i = 0; i < hdr->mail_num; ++i)
  1508.         fprintf(fp,"%s\n",(hdr->mail)[i]);
  1509.     fprintf(fp,"\n");
  1510.  
  1511.     fprintf(fp,"%s:\n",hdr->from);
  1512.     edcopy (fp);
  1513.     fclose (fp);
  1514.  
  1515.     tty_set (SAVEMODE);
  1516.  
  1517.     sprintf (cmd,"%s %s", Editor, fn);
  1518.     chdir (Orgdir);
  1519.     system (cmd);
  1520.     vns_gset (Page.h.name);
  1521.  
  1522.     new = rprompt ("still want to mail it ? ",cmd);
  1523.     if (new != NULL && (*new == 'y' || *new == 'Y'))
  1524.     {
  1525.         if (Mailfunc == NULL)
  1526.         {
  1527.             sprintf (cmd, hdr->mailcmd, fn);
  1528.             system (cmd);
  1529.             printf ("given to mailer\n");
  1530.         }
  1531.         else
  1532.             (*Mailfunc)(hdr,fn);
  1533.     }
  1534.     else
  1535.         printf ("not mailed\n");
  1536.  
  1537.     unlink (fn);
  1538.  
  1539.     tty_set (RESTORE);
  1540.     term_set (RESTART);
  1541. }
  1542.  
  1543. /*
  1544.     post a followup article, invoking editor for user after creating
  1545.     new temp file.  remove after posting.
  1546. */
  1547. static
  1548. followup (hdr)
  1549. ARTHEADER *hdr;
  1550. {
  1551.     char fn[L_tmpnam], *new, cmd [RECLEN], *rprompt();
  1552.     int i;
  1553.     FILE *f, *fopen();
  1554.     char *rindex();
  1555.  
  1556.     if (hdr->post_err != NULL)
  1557.     {
  1558.         rerrmsg(hdr->post_err);
  1559.         return;
  1560.     }
  1561.  
  1562.     tmpnam (fn);
  1563.     if ((f = fopen(fn,"w")) == NULL)
  1564.     {
  1565.         rerrmsg("can't open temp file, %s",fn);
  1566.         return;
  1567.     }
  1568.  
  1569.     for (i=0; i < hdr->post_num; ++i)
  1570.         fprintf(f,"%s\n",(hdr->post)[i]);
  1571.     fprintf(f,"\n");
  1572.  
  1573.     fprintf(f,"From article %s, by %s:\n", hdr->artid, hdr->from);
  1574.         
  1575.     edcopy (f);
  1576.     fclose (f);
  1577.     tty_set (SAVEMODE);
  1578.     sprintf (cmd,"%s %s", Editor, fn);
  1579.     chdir (Orgdir);
  1580.     system (cmd);
  1581.     vns_gset (Page.h.name);
  1582.  
  1583.     new = rprompt("still want to post it ? ",cmd);
  1584.     if (new != NULL && (*new == 'y' || *new == 'Y'))
  1585.     {
  1586.         if (Postfunc == NULL)
  1587.         {
  1588.             sprintf (cmd, hdr->postcmd, fn);
  1589.             system (cmd);
  1590.             printf ("given to posting program\n");
  1591.         }
  1592.         else
  1593.             (*Postfunc)(hdr,fn);
  1594.         save_article (fn);
  1595.     }
  1596.     else
  1597.         printf ("not posted\n");
  1598.     unlink (fn);
  1599.     tty_set (RESTORE);
  1600.     term_set (RESTART);
  1601. }
  1602.  
  1603. /*
  1604.     get user buffer, return whitespace delimited token
  1605.     buffer is allowed to overwrite prompt string.  This routine
  1606.     should only be used when the terminal is in cooked mode.
  1607.     In raw, use user_str().
  1608. */
  1609. static char *
  1610. rprompt(s,buf)
  1611. char *s,*buf;
  1612. {
  1613.     char *strtok();
  1614.  
  1615.     printf("%s",s);
  1616.     fgets (buf,RECLEN-1,stdin);
  1617.     return (strtok(buf," \t\n"));
  1618. }
  1619.  
  1620. /*
  1621.     edcopy copies article to file which user is editting for
  1622.     a reply or followup, so it may be referenced.  It places
  1623.     ED_MARK in the left hand margin.
  1624. */
  1625. static
  1626. edcopy(fp)
  1627. FILE *fp;
  1628. {
  1629.     long current;
  1630.     char buf[RECLEN];
  1631.  
  1632.     /* save position, and seek to top of article */
  1633.     current = ftell(Fpread);
  1634.     fseek (Fpread,Rew_pos,0);
  1635.  
  1636.     /* if line already begins with ED_MARK, forget about the space */
  1637.     while (fgets(buf,RECLEN-1,Fpread) != NULL)
  1638.     {
  1639.         if (buf[0] == ED_MARK)
  1640.             fprintf(fp,"%c%s",ED_MARK,buf);
  1641.         else
  1642.             fprintf(fp,"%c %s",ED_MARK,buf);
  1643.     }
  1644.  
  1645.     /* restore position */
  1646.     fseek(Fpread,current,0);
  1647. }
  1648.  
  1649. static
  1650. rot_line (s)
  1651. unsigned char *s;
  1652. {
  1653.     for ( ; *s != '\0'; ++s)
  1654.     {
  1655.         if (*s >= 'A' && *s <= 'Z')
  1656.         {
  1657.             *s += Rot;
  1658.             if (*s > 'Z')
  1659.                 *s -= 26;
  1660.             continue;
  1661.         }
  1662.         if (*s >= 'a' && *s <= 'z')
  1663.         {
  1664.             *s += Rot;
  1665.             if (*s > 'z')
  1666.                 *s -= 26;
  1667.         }
  1668.     }
  1669. }
  1670.  
  1671. /*
  1672. ** output record.  folds record to terminal width on word boundaries,
  1673. ** returning number of lines output.  If limit is reached, remainder
  1674. ** of buffer waiting to be output is returned.  Processes several
  1675. ** special characters:
  1676. **    form-feed - return "lim" lines so we stop on that line
  1677. **    tabs - counts "expanded" width
  1678. **    backspace - assumes they work, -1 width unless in first col.
  1679. **    bell - pass through with zero width
  1680. **    newline - end of record.
  1681. **    del - turns into '_'
  1682. **    other control - 'A' - 1 added ('01' = ctl-A).  Makes escape = "[".
  1683. **        (prevents "letter bombs" containing inappropriate control
  1684. **            sequences for the terminal).
  1685. **
  1686. ** Sets Lookahead pointer to remainder of line or NULL.
  1687. */
  1688. static
  1689. do_out(s,lim)
  1690. char *s;
  1691. int lim;
  1692. {
  1693.     int len,i;
  1694.     char cs,*word,*start;
  1695.  
  1696.     Lookahead = NULL;
  1697.     if (s == NULL)
  1698.         return(0);
  1699.     len = 0;
  1700.     start = word = s;
  1701.  
  1702.     /*
  1703.     ** NOTE: "normal" return is buried inside switch, at newline
  1704.     ** ending record
  1705.     */
  1706.     for (i=0; i < lim; ++i)
  1707.     {
  1708.         for ( ; len < C_allow; ++s)
  1709.         {
  1710.             switch (*s)
  1711.             {
  1712.             case '\n':
  1713.                 *s = '\0';    /* fall through */
  1714.             case '\0':
  1715.                 printf("%s\n",start);
  1716.                 return(i+1);
  1717.             case '\t':
  1718.                 len = ((len/PERTAB)+1)*PERTAB;
  1719.                 word = s;
  1720.                 break;
  1721.             case '\b':
  1722.                 if (len > 0)
  1723.                     --len;
  1724.                 break;
  1725.             case '\014':
  1726.                 *s = ' ';
  1727.                 i = lim-1;    /* fall through */
  1728.             case ' ':
  1729.                 word = s+1;
  1730.                 ++len;
  1731.                 break;
  1732.             case '\177':
  1733.                 *s = '_';
  1734.                 ++len;
  1735.                 break;
  1736.             default:
  1737.                 if (*s < ' ')
  1738.                     *s += 'A' - 1;
  1739.                 ++len;        /* fall through */
  1740.             case '\07':
  1741.                 break;
  1742.             }
  1743.         }
  1744.         cs = *s;
  1745.         *s = '\0';
  1746.         if ((len = strlen(word)) < BACKTRACK)
  1747.         {
  1748.             *s = cs;
  1749.             s = word;
  1750.             cs = *s;
  1751.             *s = '\0';
  1752.         }
  1753.         else
  1754.             len = 0;
  1755.         printf("%s\n",start);
  1756.         start = s;
  1757.         *s = cs;
  1758.     }
  1759.     Lookahead = start;
  1760.     return(lim);
  1761. }
  1762.  
  1763. static
  1764. save_article(tempfname)
  1765. char *tempfname;
  1766. {
  1767.     FILE *in, *out;
  1768.     int c;
  1769.     time_t timenow, time();
  1770.     char *today, *ctime();
  1771.  
  1772.     if ((in = fopen(tempfname, "r")) == NULL)
  1773.         return;
  1774.     if ((out = fopen(Ccfile, "a")) == NULL)
  1775.     {
  1776.         fclose(in);
  1777.         return;
  1778.     }
  1779.     timenow = time((time_t)0);
  1780.     today = ctime(&timenow);
  1781.     fprintf(out,"From vn %s",today);
  1782.     while ((c=getc(in)) != EOF)
  1783.         putc(c, out);
  1784.     putc('\n', out);
  1785.     fclose(in);
  1786.     fclose(out);
  1787.     printf ("a copy has been saved in %s\n", Ccfile);
  1788. }
  1789.  
  1790. /*
  1791.     send article to printer
  1792. */
  1793. static
  1794. printr ()
  1795. {
  1796.     char cmd[RECLEN];
  1797.     char fn[L_tmpnam];
  1798.     long savepos;
  1799.     FILE *f;
  1800.  
  1801.     tmpnam (fn);
  1802.     if ((f = fopen(fn,"w")) == NULL)
  1803.     {
  1804.         rerrmsg("can't open temp file, %s",fn);
  1805.         return;
  1806.     }
  1807.  
  1808.     savepos = ftell(Fpread);
  1809.     rewind(Fpread);
  1810.     while (fgets(cmd,RECLEN-1,Fpread) != NULL)
  1811.         fputs(cmd,f);
  1812.     fclose(f);
  1813.     fseek(Fpread,savepos,0);
  1814.  
  1815.     tty_set (SAVEMODE);
  1816.     printf("Sent to printer\n");
  1817.     sprintf (cmd,"%s %s 2>/dev/null",Printer,fn);
  1818.     system (cmd);
  1819.     tty_set (RESTORE);
  1820.     unlink (fn);
  1821. }
  1822.  
  1823. /*
  1824.     search article for specified search pattern, returning the line on which
  1825.         it is found in buf, a null buffer otherwise. The input file will
  1826.         be positioned either after the line on which the pattern is
  1827.         found, or unaaltered if match fails.
  1828. */
  1829. static
  1830. searcher (buf)
  1831. char    *buf;
  1832. {
  1833.     static char    searchstr[RECLEN] = "";
  1834.     char    lasave[RECLEN];
  1835.     char    *reg, *regcmp(), *regex();
  1836.     long    current;
  1837.     int    orlines;
  1838.  
  1839.     /* save position, then request search pattern */
  1840.     current = ftell(Fpread);
  1841.     orlines = Rlines;
  1842.  
  1843.     sprintf (lasave,SEARCHFORM,searchstr);
  1844.     user_str (searchstr,lasave,0,searchstr);
  1845.  
  1846.     /* Now compile the search string */
  1847.     if(( reg = regcmp(searchstr, (char *)0)) == NULL) {
  1848.         rerrmsg("Invalid search string \"%s\"", searchstr);
  1849.         *buf = '\0';
  1850.         return;
  1851.     }
  1852.  
  1853.     /* try lookahead buffer first */
  1854.     if (Lookahead != NULL && regex(reg,Lookahead) != NULL)
  1855.     {
  1856.         strcpy(buf,Lookahead);
  1857.         regfree(reg);
  1858.         return;
  1859.     }
  1860.  
  1861.     /* Lookahead can point into buf */
  1862.     if (Lookahead != NULL)
  1863.         strcpy(lasave,Lookahead);
  1864.  
  1865.     /* now start reading lines, rotating if necessary and do search */
  1866.     while (fgets(buf,RECLEN-1,Fpread) != NULL)
  1867.     {
  1868.         if (Rot != 0 && Rlines >= Hlines)
  1869.             rot_line(buf);
  1870.         ++Rlines;
  1871.         if( regex(reg, buf) != NULL ){    /* Got it */
  1872.             rerrmsg("\n\tSkipping ....\n\n");
  1873.             regfree(reg);
  1874.             return;
  1875.         }
  1876.     }
  1877.  
  1878.     /* no dice, so restore position */
  1879.     regfree(reg);
  1880.     rerrmsg("Cannot find string \"%s\" in remainder of article", searchstr);
  1881.     fseek(Fpread,current,0);
  1882.     Rlines = orlines;
  1883.     if (Lookahead != NULL)
  1884.         strcpy(buf,lasave);
  1885.     else
  1886.         *buf = '\0';
  1887. }
  1888.  
  1889. /*
  1890. ** print a reverse video error message while reading an article.
  1891. */
  1892. static
  1893. rerrmsg(s,a,b,c,d,e)
  1894. char *s;
  1895. long a,b,c,d,e;
  1896. {
  1897.     term_set (ONREVERSE);
  1898.     printf("\n ");
  1899.     printf(s,a,b,c,d,e);
  1900.     printf(" \07\n");
  1901.     term_set (OFFREVERSE);
  1902. }
  1903. SHAR_EOF
  1904. fi # end of overwriting check
  1905. echo shar: extracting "'config.h'" '(4043 characters)'
  1906. if test -f 'config.h'
  1907. then
  1908.     echo shar: will not over-write existing file "'config.h'"
  1909. else
  1910. cat << \SHAR_EOF > 'config.h'
  1911. /*
  1912. ** vn news reader.
  1913. **
  1914. ** config.h - system configuration parameters
  1915. **
  1916. ** see copyright disclaimer / history in vn.c source file
  1917. */
  1918.  
  1919. #define DEF_ED "/usr/ucb/vi"    /* editor to use if no EDITOR variable */
  1920. #define DEF_PS1 "$ "        /* ! command prompt if no PS1 */
  1921. #define DEF_SAVE ""        /* save file */
  1922.  
  1923. #define DEF_PRINT "/usr/ucb/lpr"        /* print command */
  1924.  
  1925. #define DEF_CCFILE "author_copy"
  1926. #define DEF_KEYXLN ".vnkey"
  1927.  
  1928. /*
  1929. ** this is the "pre-typed" string the user will be presented with
  1930. ** in answer to the "update" question following the QUIT command.
  1931. ** Set to "" if you don't like it answering "yes" for you, or "y"
  1932. ** if you only want to have to erase one character to say "no", etc.
  1933. */
  1934. #define QUIT_ANSWER "yes"
  1935.  
  1936. /*
  1937. ** default terminal assumed if TERM variable is unset.  Since TERM has to
  1938. ** be set for most UNIX tools, you probably want to make this something
  1939. ** which will cause failure, unless EVERYBODY has the same kind of terminal
  1940. ** or you don't really use a standard UNIX environment.
  1941. */
  1942. #define DEF_TERM "<unspecified TERM variable>"
  1943.  
  1944. /*
  1945. ** foreground flag for messages.  applies only if JOBCONTROL undefined
  1946. ** (SYS V). set to 1 to see newsgroup messages, etc. during reading phase,
  1947. ** 0 for "silent" operation - be warned that this may suppress some
  1948. ** non-fatal diagnostic messages - find all references to fgprintf to
  1949. ** see what is suppressed.
  1950. */
  1951. #define NOJOB_FG 1
  1952.  
  1953. /*
  1954. ** arrow key treatment.  If PAGEARROW is defined, right and left arrow
  1955. ** keys will be synonyms for <return> (next-page) and <backspace> (previous).
  1956. ** Otherwise, the right arrow will function as down, and the left as up.
  1957. ** Made configurable because while there is no lateral motion on the screen
  1958. ** to associate with the right and left arrows, you might not like them
  1959. ** changing pages on you.
  1960. */
  1961. #define PAGEARROW
  1962.  
  1963. /*
  1964. ** if USEVS is defined, terminal initialization / exit for vn will include the
  1965. ** "vs"/"ve" pair as well as "ti"/"te".  This doesn't matter on a lot of
  1966. ** terminals, but may make vn display behaviour closer to "vi" since vs/ve
  1967. ** is vi's "visual mode" sequence.  For instance, I believe the commonly
  1968. ** used definitions for these strings on multi-page concepts allows the
  1969. ** program to run in the first page of the terminal, preserving the more
  1970. ** recent part of your session on exit
  1971. **
  1972. ** #define USEVS
  1973. */
  1974.  
  1975. /*
  1976. ** temp file name template for mktemp().  Used in tmpnam.c, does not apply
  1977. ** if you use a system library tmpnam().   BE CAREFUL - VNTEMPNAME MUST
  1978. ** contain a string of 6 X's for mktemp() (actually, a place where 6 X's
  1979. ** are intended to go).  TMP_XOFFSET absolutely MUST point to the first of
  1980. ** the X's.  Yes, writing into a literal string is sloppy.  To the best of
  1981. ** my knowledge, tmpnam.c is the only place you'll find vn code doing it.
  1982. ** We make this configurable in case you want temp files somewhere else.
  1983. */
  1984. #define VNTEMPNAME "/usr/tmp/vnXXXXXX"
  1985. #define TMP_XOFFSET 11
  1986.  
  1987. /*
  1988. ** VNLOGFILE and VNSTATFILE.  If these files EXIST, the corresponding data
  1989. ** collection will be turned on.  If they don't it will be turned off.
  1990. ** To turn it back on again, create the files empty.  Garbage in VNLOGFILE
  1991. ** won't hurt collection but VNSTATFILE requires very strict syntax, so
  1992. ** make sure its always an empty file or EXACTLY the right syntax.  See stat.c
  1993. **
  1994. ** VNLOGFILE logs user sessions.  VNSTATFILE keeps a running breakdown
  1995. ** of newsgroup activity.  I add these with some hesitancy, as I find
  1996. ** use of things like this for Gestapo-like purposes repugnant in the
  1997. ** extreme.  However, they can also be useful for system tuning purposes
  1998. ** such as verifying what newsgroups are being read, and when load on
  1999. ** the system due to newsreading is occurring.
  2000. **
  2001. ** If VNLOGFILE and VNSTATFILE are NOT DEFINED, the code for doing logging
  2002. ** and statistical collection will not be compiled in, saving some overhead,
  2003. ** and avoiding calls to system functions like ctime() and time() which may
  2004. ** have system dependent quirks.
  2005. **
  2006. #define VNLOGFILE "/usr/rti/fe/bobm/vn.log"
  2007. #define VNSTATFILE "/usr/rti/fe/bobm/vn.stat"
  2008. */
  2009. SHAR_EOF
  2010. fi # end of overwriting check
  2011. #    End of shell archive
  2012. exit 0
  2013.